:-dynamic(barco/4).
%jugar
%mostrarTablero(T)
%estadoFinal(T)
%ataque(T0, T1, F, C)
%barco(Ci,Fi,dir,tam).
%barco(0,2,h,3).
%barco(3,0,v,2).
%barco(0,0,h,1).


%C columna, E elemento o caracter a dibujar, L lista dibujada.
dibujarFila(0,_,[]):- !.
dibujarFila(C,E,L):- C1 is C-1, 
		   dibujarFila(C1,E,X),
		   append(X,[E],L).

%F filas, C columnas, T tablero a retornar.
tableroInicial(0,_,[]):- !.
tableroInicial(F, C, T) :- dibujarFila(C,a,LF), 
			   F1 is F-1, 
   			   tableroInicial(F1,C,X), 
			   append(X,[LF],T).

%P posicion, [H|R] lista a examinar.
%esta funcion indica si en la posicion dada por P, hay o no agua.
tieneElementoFila(0,[H|_],E) :- E=H, !.
tieneElementoFila(P,[_|R],E) :- P1 is P-1, 
		      		tieneElementoFila(P1,R,E).

%T0 tablero a examinar.
%esta funcion indica si en la posicion dada por (X,Y) hay o no el elemento especificado (a,f,g,h).
hayElemento(T0,X,Y,E) :-   obtenerSublista(T0, Y,Fila),
		           tieneElementoFila(X,Fila,E). 

%_[H|R] tablero, N numero de lista o fila a retornar, L lista o fila deseada.
%esta funcion obtiene la fila de un tablero especificada por N.
obtenerSublista([H|_], 0, L) :- L=H, !.
obtenerSublista([_|R], N, L) :- N1 is N-1,
			        obtenerSublista(R,N1,L).

%_[H|R] lista original, N numero de elementos, Lf lista final
%Esta funcion obtiene los primeros N elementos de la lista especificada por [H|R]. 
obtenerInicio(_,0,[]):- !.
obtenerInicio([H|R],N,Lf) :- 	X1 is N-1,
				obtenerInicio(R,X1,A),
				append([H],A,Lf).

%L lista original, N numero de elementos, Lf lista final
%Esta funcion obtiene los ultimos N elementos de la lista L. 
%Fume al estilo Novich
obtenerFin(L,N,Lf):- 	length(L,Tam),
			N > Tam,
			append([],[],Lf),!.
			
obtenerFin(L,N,Lf):-	length(L,Tam),
			N =< Tam,
			length(Lf,N), %se crea una lista de tam N, con cualquier cosa
			append(_,Lf,L),
			!. %Cuando se hace el append, necesariamente Lf va a tener los ultimos N elementos de la lista L.

%L lista inicial, P posicion, Edo o caracter a dibujar, Lf lista final.
%Esta funcion cambia en la lista L, especificamente en la posicion P, un caracter especificado por Edo.
cambiarEdo(L,P,Edo,Lf):-length(L,Tam), 
			obtenerInicio(L,P,A),
			append(A,[Edo],B),
			C1 is Tam-P-1,
			obtenerFin(L,C1,C),
			append(B,C,Lf).

mostrarTablero([]):-write(''),!.
mostrarTablero([H|R]):- mostrarElemento(H),nl,
			mostrarTablero(R).

mostrarElemento([]):- write(''),!.
mostrarElemento([H|R]):- write(H),
			 write(' '),
			 mostrarElemento(R).

%___________________________________________________________________________________________


hayBarco(X,Y) :- barco(X,Y,_,_),!. 

hayBarco(X,Y):- barco(X,Yi,v,Tam),
        	Y >= Yi,
                P is Y-Yi,
                P<Tam,!.

hayBarco(X,Y):- barco(Xi,Y,h,Tam),
        	X >= Xi,
                P is X-Xi,
                P<Tam,!.

		
% rafael yo

esVOH(v).
esVOH(h).

cabeEnTablero(_,Y0,v,T,_,Y):- 	Y1 is Y0+T, 
				Y1 =< Y.
cabeEnTablero(X0,_,h,T,X,_):- 	X1 is X0+T, 
				X1 =< X.

solicitarDatosBarco(_,_,0).
solicitarDatosBarco(F,C,N):- 	write('Informacion de Barco: '),nl,
				write('Tamano: '),read(T),
				write('Direccion: '), read(D), esVOH(D),
                            	write('Fila Inicial: '), read(Fi),
                             	write('Columna Inicial: '), read(Ci),
				cabeEnTablero(Ci,Fi,D,T,C,F),
				assert(barco(Ci,Fi,D,T)),
				N1 is N-1, solicitarDatosBarco(F,C,N1),!.

pedirDatos(F,C,Nb):- write('Num. de Filas: '), read(F),
			F > 0, F =< 20,
		    write('Num. de Columnas: '), read(C),
		    C > 0, C =< 20,
		    write('Cant. de Barcos: '), read(Nb),
		    solicitarDatosBarco(F,C,Nb).

jugar:- pedirDatos(F,C,Nb), 
	tableroInicial(F,C,T0),
	ataque(T0,T1,F,C).

%Se supone que todos los barcos estan hundidos cuando no existen mas barcos en la base de conocimientos.
hundirBarco(Ci,Fi,D,Tam,T0,T):- barco(Ci,Fi,D,Tam),
				dibujarBarcoHundido(Ci,Fi,D,Tam,T0,T).

cambiarEdoCompleto(Fila,P,Tam,FilaCambiada,Acum):- Acum >= Tam,
						   append([],Fila,FilaCambiada),!.
cambiarEdoCompleto(Fila,P,Tam,FilaCambiada,Acum):- Acum < Tam,
						   cambiarEdo(Fila,P,h,FilaC),
						   Acum1 is Acum+1,
						   X is P+1,
						   cambiarEdoCompleto(FilaC,X,Tam,FilaCambiada,Acum1).


dibujarBarcoHundido(Ci,Fi,h,Tam,T0,T):- obtenerSublista(T0,Fi,Fila),
					cambiarEdoCompleto(Fila,Ci,Tam,FilaCambiada,0),
					obtenerInicio(T0,Fi,L1),
					append(L1,[FilaCambiada],L2),
					length(L2,TamAux),
					length(T0,TamTab),
					Aux is TamTab-TamAux,
					obtenerFin(T0,Aux,L3),
					append(L2,L3,T).
					%mostrarTablero(T).

dibujarBarcoHundido(_,_,v,Tam,T0,T):- 	Tam =< 0,
					append([],T0,T),
					%mostrarTablero(T),
					!.
dibujarBarcoHundido(Ci,Fi,v,Tam,T0,T):- Tam > 0,
					obtenerSublista(T0,Fi,Fila),
					cambiarEdo(Fila,Ci,h,FilaCambiada),
					obtenerInicio(T0,Fi,L1),
					append(L1,[FilaCambiada],L2),
					length(L2,TamAux),
					length(T0,TamTab),
					Aux is TamTab-TamAux,
					obtenerFin(T0,Aux,L3),
					append(L2,L3,T1),
					Y is Fi +1,
					Tam1 is Tam-1,
					dibujarBarcoHundido(Ci,Y,v,Tam1,T1,T).


%dibujarBarcoHundido(3,0,v,2,[[a,a,a,a],[a,a,a,a],[a,a,a,a],[a,a,a,a]],T),mostrarTablero(T).
%dibujarBarcoHundido(3,0,v,2,[[a,a,a,a],[a,a,a,a],[a,a,a,a],[a,a,a,a]],T),dibujarBarcoHundido(0,0,h,2,T,T1),dibujarBarcoHundido(0,2,h,3,T1,T2),mostrarTablero(T2).

%_____________________________________________________________________________________________________________________

%Esta funcion retorna en N el numero de casillas de todos los barcos, esten o no hundidos.

totalPosicionesBarcos(C,F,N):- totalPosicionesBarcos(C,F,0,0,0,N),!.
totalPosicionesBarcos(C,F,X,Y,N,N) :- X < C,
								      Y >= F,!.
								 
totalPosicionesBarcos(C,F,X,Y,I,N) :- X >= C,
                                      Y < F,
                                      Y1 is Y+1,
                                      X1 is 0,
                                      totalPosicionesBarcos(C,F,X1,Y1,I,N),!.
				  
totalPosicionesBarcos(C,F,X,Y,I,N):- X < C,
                                     Y < F,
                                     hayBarco(X,Y),
                                     X1 is X+1,
                                     Ni is I +1,
                                     totalPosicionesBarcos(C,F,X1,Y,Ni,N),!.

totalPosicionesBarcos(C,F,X,Y,I,N):- X < C,
                                     Y < F,
                                     not(hayBarco(X,Y)),
                                     X1 is X+1,
                                     totalPosicionesBarcos(C,F,X1,Y,I,N),!.
									 
%_____________________________________________________________________________________________________________________

%Esta funcion devuelve el numero de h que hay en el tablero

totalH(C,F,T,N):- totalH(T,C,F,0,0,0,N),!.
totalH(_,C,F,X,Y,N,N) :- X < C,
			 Y >= F,!.
								 
totalH(T,C,F,X,Y,I,N) :- X >= C,
                         Y < F,
                         Y1 is Y+1,
                         X1 is 0,
                         totalH(T,C,F,X1,Y1,I,N),!.
				  
totalH(T,C,F,X,Y,I,N):- X < C,
                        Y < F,
                        hayElemento(T,X,Y,h),
                        X1 is X+1,
                        Ni is I +1,
                        totalH(T,C,F,X1,Y,Ni,N),!.

totalH(T,C,F,X,Y,I,N):- X < C,
                        Y < F,
                        not(hayElemento(T,X,Y,h)),
                        X1 is X+1,
                        totalH(T,C,F,X1,Y,I,N),!.
						
estadoFinal(T):- length(T,F),
                 obtenerSublista(T,0,Fila),
				 length(Fila,C),
				 totalPosicionesBarcos(C,F,N),
				 totalH(C,F,T,N2), N=N2,!.

%totalH(4,4,[[h,h,a,h],[a,a,a,h],[h,h,h,a],[a,a,a,a]],N).
%tableroInicial(4,4,T0),estadoFinal(T0).

% muestra la secuencia de tableros que corresponden a una solucion factible.
mostrarSolucion([]):-!.
mostrarSolucion([H|R]):- mostrarTablero(H), nl,
                         mostrarSolucion(R).
						 

						 
%___________________________________________________________________________________________

ataque(T0,T1,F,C) :- write('Cant. de proyectiles disponibles: '), read(B), nl,
		     mostrarTablero(T0),nl,
                     ataqueRecursivo(T0,T1,F,C,0,0,[],Sol),
		     mostrarSolucion(Sol).
		             
ataqueRecursivo(T0,T1,F,C,X,Y,L,Sol) :- X >= C,
				  	Y < F,
				  	Y1 is Y+1,
				 	X1 is 0,
				  	ataqueRecursivo(T0,T1,F,C,X1,Y1,L,Sol).

ataqueRecursivo(T,T,F,C,X,Y,Sol,Sol) :- X < C,
		    	  	        Y >= F,!.

ataqueRecursivo(T,T,F,C,X,Y,Sol,Sol) :-  X < C,
				         Y < F,
				         estadoFinal(T),!.

ataqueRecursivo(T0,T,F,C,X,Y,L,Sol) :-  X < C,
                                        Y < F,
                                        not(estadoFinal(T0)),
                                        ataque(T0,T1,F,C,X,Y),
                                        append(L,[T1],Sol1),
                                        X1 is X+1,
                                        ataqueRecursivo(T1,T,F,C,X1,Y,Sol1,Sol),!.


%ataque([[a,a,a,a],[a,a,a,a],[a,a,a,a],[a,a,a,a]],T1,4,4,0,2), ataque(T1,T2,4,4,1,2), ataque(T2,T3,4,4,2,2).

%Ataque a agua
ataque(T0,T1,F,C,X,Y):- not(hayBarco(X,Y)),
			hayElemento(T0,X,Y,a), %hayAGua
			dibujarAtaque(T0,T1,F,C,X,Y,f),!.

%Ataque a un barco no hundido
ataque(T0,T1,F,C,X,Y):- hayBarco(X,Y),
			dibujarAtaque(T0,T1,F,C,X,Y,g),
			not(barcoHundido(T1,X,Y)),!.

%Ataque a ultima casilla de barco no hundido
ataque(T0,T1,F,C,X,Y):- hayBarco(X,Y),
			dibujarAtaque(T0,T,F,C,X,Y,g),
			barcoHundido(T,X,Y), %indica si un barco se hunde
		        obtenerDatos(X,Y,Ci,Fi,Dir,Tam),
			hundirBarco(Ci,Fi,Dir,Tam,T,T1),!. %hunde el barco


/*ataque(T0,T1,F,C,X,Y):- 
			hayElemento(T0,X,Y,f), %hayFallo
			!.
*/


dibujarAtaque(T0,T1,F,_,X,Y,E) :- obtenerSublista(T0, Y, Fila),
				  cambiarEdo(Fila,X,E,Filacambiada),
				  obtenerInicio(T0,Y,L1),
				  append(L1,[Filacambiada],L2),
				  length(L2,Tam),
				  Aux is F-Tam,
				  obtenerFin(T0,Aux,L3),
				  append(L2,L3,T1),
				  %mostrarTablero(T1),
				  !.


%mostrarSolucion([[[a,a,a,g],[a,a,a,a],[a,a,a,a],[a,a,a,a]],[[a,a,a,h],[a,a,a,h],[a,a,a,a],[a,a,a,a]]]).


%_DAYANA

%_Nuevo: Dado un (X,Y) cualquiera obtengo los datos que corresponden al barco.
obtenerDatos(X,Y,X,Y,Dir,Tam) :- barco(X,Y,Dir,Tam),!. 

obtenerDatos(X,Y,Ci,Fi,Dir,Tam):- barco(X,Y1,Dir,Tam),
				 Dir=v,
				 Ci is X,
				 Fi is Y1,
		 		 Y >= Y1,
                		 P is Y-Y1,
               			 P<Tam,!.

obtenerDatos(X,Y,Ci,Fi,Dir,Tam):- barco(X1,Y,Dir,Tam),
				 Dir=h,
				 Ci is X1,
				 Fi is Y,
		 		 X >= X1,
                		 P is X-X1,
                		 P<Tam,!.


%_Esta funcion recorre un tablero, dado una posicion inicial de barco, para saber si un barco se hunde o no.
recorrerTablero(T0,Xc,Y,Dir,Tam,Acum):- Dir=h, Acum >= Tam,!.
recorrerTablero(T0,X,Yc,Dir,Tam,Acum):- Dir=v, Acum >= Tam,!.
recorrerTablero(T0,Xc,Y,Dir,Tam,Acum):- Dir=h,	
				  	Acum < Tam,
					Acum1 is Acum+1, 
				   	hayElemento(T0,Xc,Y,g),
				   	X1 is Xc+1,
				   	recorrerTablero(T0,X1,Y,Dir,Tam,Acum1),!.

recorrerTablero(T0,X,Yc,Dir,Tam,Acum):- Dir=v,	
				   	Acum < Tam,
					Acum1 is Acum+1, 
				   	hayElemento(T0,X,Yc,g),
				   	Y1 is Yc+1,
				   	recorrerTablero(T0,X,Y1,Dir,Tam,Acum1),!.

barcoHundido(T0,X,Y) :- obtenerDatos(X,Y, X0,Y0,D,T),
		        recorrerTablero(T0,X0,Y0,D,T,0).

